bitkeeper revision 1.1327.2.13 (4270d6c35WpxFmhdkREjmSvk82s-Bg)
authormjw@wray-m-3.hpl.hp.com <mjw@wray-m-3.hpl.hp.com>
Thu, 28 Apr 2005 12:27:47 +0000 (12:27 +0000)
committermjw@wray-m-3.hpl.hp.com <mjw@wray-m-3.hpl.hp.com>
Thu, 28 Apr 2005 12:27:47 +0000 (12:27 +0000)
Merge Jeremy's pygrub bootloader patch.

Signed-off-by: Jeremy Katz <katzj@redhat.com>
Signed-off-by: Mike Wray <mike.wray@hp.com>
16 files changed:
.rootkeys
tools/Makefile
tools/pygrub/Makefile [new file with mode: 0644]
tools/pygrub/setup.py [new file with mode: 0644]
tools/pygrub/src/GrubConf.py [new file with mode: 0644]
tools/pygrub/src/__init__.py [new file with mode: 0644]
tools/pygrub/src/fsys/__init__.py [new file with mode: 0644]
tools/pygrub/src/fsys/ext2/__init__.py [new file with mode: 0644]
tools/pygrub/src/fsys/ext2/ext2module.c [new file with mode: 0644]
tools/pygrub/src/fsys/ext2/test.py [new file with mode: 0644]
tools/pygrub/src/pygrub [new file with mode: 0644]
tools/python/xen/xend/XendBootloader.py [new file with mode: 0644]
tools/python/xen/xend/XendDomainInfo.py
tools/python/xen/xend/server/blkif.py
tools/python/xen/xm/create.py
tools/xfrd/xfrd.c

index 2037a998281709904147a97667679bcb6387f391..e53f3b2576bef0d7c8aefd66fc694332127780bd 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 4107986eMWVdBoz4tXYoOscpN_BCYg tools/misc/xensv
 4056f5155QYZdsk-1fLdjsZPFTnlhg tools/misc/xensymoops
 40cf2937dqM1jWW87O5OoOYND8leuA tools/misc/xm
+4270cc81g3nSNYCZ1ryCMDEbLtMtbQ tools/pygrub/Makefile
+4270cc81EIl7NyaS3Av6IPRk2c2a6Q tools/pygrub/setup.py
+4270cc81t7eNCDp4Bhbh58p1CNxaCQ tools/pygrub/src/GrubConf.py
+4270d6c2fWF4r5-zF1pSuAFwUZS0aA tools/pygrub/src/__init__.py
+4270cc81CzKMiujDPWcaYhu709vGXw tools/pygrub/src/fsys/__init__.py
+4270cc81RTIiq9si0dI4YRTRE4KRMw tools/pygrub/src/fsys/ext2/__init__.py
+4270cc81YCYa4pexivBD2NdLE2F_Pg tools/pygrub/src/fsys/ext2/ext2module.c
+4270cc81o4BL5e8Cs87aSi8EXA5NtQ tools/pygrub/src/fsys/ext2/test.py
+4270cc81TS6L_tEO6wSp5wcURcpldQ tools/pygrub/src/pygrub
 40c9c468icGyC5RAF1bRKsCXPDCvsA tools/python/Makefile
 40ffc44dOwe1CcYXGCkYHdG_NxcccA tools/python/logging/logging-0.4.9.2/PKG-INFO
 40ffc44dpqpgqgrnLfR70PsiBc3liA tools/python/logging/logging-0.4.9.2/README.txt
 40c9c468Um_qc66OQeLEceIz1pgD5g tools/python/xen/xend/EventServer.py
 40c9c468QJTEuk9g4qHxGpmIi70PEQ tools/python/xen/xend/PrettyPrint.py
 40e15b7eeQxWE_hUPB2YTgM9fsZ1PQ tools/python/xen/xend/Vifctl.py
+4270cc81xbweGYhsM4326N3dX1bGHQ tools/python/xen/xend/XendBootloader.py
 40c9c4688m3eqnC8fhLu1APm36VOVA tools/python/xen/xend/XendClient.py
 40c9c468t6iIKTjwuYoe-UMCikDcOQ tools/python/xen/xend/XendConsole.py
 40c9c468WnXs6eOUSff23IIGI4kMfQ tools/python/xen/xend/XendDB.py
index da2fe19a7245d3ff35edbad5e8f39feea690a2d3..9f4a601d023558d62d35379f5a820327f0e0371f 100644 (file)
@@ -11,6 +11,7 @@ SUBDIRS += python
 SUBDIRS += xfrd
 SUBDIRS += xcs
 SUBDIRS += ioemu
+SUBDIRS += pygrub
 
 .PHONY: all install clean check check_clean
 
diff --git a/tools/pygrub/Makefile b/tools/pygrub/Makefile
new file mode 100644 (file)
index 0000000..a676cdf
--- /dev/null
@@ -0,0 +1,18 @@
+
+XEN_ROOT = ../..
+include $(XEN_ROOT)/tools/Rules.mk
+
+all: build
+build:
+       CFLAGS="$(CFLAGS)" python setup.py build
+
+ifndef XEN_PYTHON_NATIVE_INSTALL
+install: all
+       CFLAGS="$(CFLAGS)" python setup.py install --home="$(DESTDIR)/usr"
+else
+install: all
+       CFLAGS="$(CFLAGS)" python setup.py install --root="$(DESTDIR)"
+endif
+
+clean:
+       rm -rf build *.pyc *.pyo *.o *.a *~
diff --git a/tools/pygrub/setup.py b/tools/pygrub/setup.py
new file mode 100644 (file)
index 0000000..193c160
--- /dev/null
@@ -0,0 +1,25 @@
+from distutils.core import setup, Extension
+import os
+
+extra_compile_args  = [ "-fno-strict-aliasing", "-Wall", "-Werror" ]
+
+# in a perfect world, we'd figure out the fsys modules dynamically
+ext2 = Extension("grub.fsys.ext2._pyext2",
+                 extra_compile_args = extra_compile_args,
+                 libraries = ["ext2fs"],
+                 sources = ["src/fsys/ext2/ext2module.c"])
+
+setup(name='pygrub',
+      version='0.1',
+      description='Boot loader that looks a lot like grub for Xen',
+      author='Jeremy Katz',
+      author_email='katzj@redhat.com',
+      license='GPL',
+      package_dir={'grub': 'src'},
+      scripts = ["src/pygrub"],
+      packages=['grub',
+                'grub.fsys',
+                'grub.fsys.ext2'],
+      ext_modules = [ext2]
+      )
+               
diff --git a/tools/pygrub/src/GrubConf.py b/tools/pygrub/src/GrubConf.py
new file mode 100644 (file)
index 0000000..3603b72
--- /dev/null
@@ -0,0 +1,229 @@
+#
+# GrubConf.py - Simple grub.conf parsing
+#
+# Copyright 2005 Red Hat, Inc.
+# Jeremy Katz <katzj@redhat.com>
+#
+# This software may be freely redistributed under the terms of the GNU
+# general public license.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+import os, sys
+import logging
+
+def grub_split(s, maxsplit = -1):
+    """Split a grub option screen separated with either '=' or whitespace."""
+    eq = s.find('=')
+    if eq == -1:
+        return s.split(None, maxsplit)
+
+    # see which of a space or tab is first
+    sp = s.find(' ')
+    tab = s.find('\t')
+    if (tab != -1 and tab < sp) or (tab != -1 and sp == -1):
+        sp = tab
+
+    if eq != -1 and eq < sp or (eq != -1 and sp == -1):
+        return s.split('=', maxsplit)
+    else:
+        return s.split(None, maxsplit)
+
+def get_path(s):
+    """Returns a tuple of (GrubDiskPart, path) corresponding to string."""
+    if not s.startswith('('):
+        return (None, s)
+    idx = s.find(')')
+    if idx == -1:
+        raise ValueError, "Unable to find matching ')'"
+    d = s[:idx]
+    return (GrubDiskPart(d), s[idx + 1:])
+
+class GrubDiskPart(object):
+    def __init__(self, str):
+        if str.find(',') != -1:
+            (self.disk, self.part) = str.split(",", 2)
+        else:
+            self.disk = str
+            self.part = None
+
+    def __repr__(self):
+        if self.part is not None:
+            return "d%dp%d" %(self.disk, self.part)
+        else:
+            return "d%d" %(self,disk,)
+
+    def get_disk(self):
+        return self._disk
+    def set_disk(self, val):
+        val = val.replace("(", "").replace(")", "")
+        self._disk = int(val[2:])
+    disk = property(get_disk, set_disk)
+
+    def get_part(self):
+        return self._part
+    def set_part(self, val):
+        if val is None:
+            self._part = val
+            return
+        val = val.replace("(", "").replace(")", "")
+        self._part = int(val)
+    part = property(get_part, set_part)
+
+class GrubImage(object):
+    def __init__(self, lines):
+        self._root = self._initrd = self._kernel = self._args = None
+        for l in lines:
+            (com, arg) = grub_split(l, 1)
+
+            if self.commands.has_key(com):
+                if self.commands[com] is not None:
+                    exec("%s = r\"%s\"" %(self.commands[com], arg.strip()))
+                else:
+                    logging.info("Ignored image directive %s" %(com,))
+            else:
+                logging.warning("Unknown image directive %s" %(com,))
+
+    def __repr__(self):
+        return ("title: %s\n" 
+                "  root: %s\n"
+                "  kernel: %s\n"
+                "  args: %s\n"
+                "  initrd: %s" %(self.title, self.root, self.kernel,
+                                   self.args, self.initrd))
+
+    def set_root(self, val):
+        self._root = GrubDiskPart(val)
+    def get_root(self):
+        return self._root
+    root = property(get_root, set_root)
+
+    def set_kernel(self, val):
+        if val.find(" ") == -1:
+            self._kernel = get_path(val)
+            self._args = None
+            return
+        (kernel, args) = val.split(None, 1)
+        self._kernel = get_path(kernel)
+        self._args = args
+    def get_kernel(self):
+        return self._kernel
+    def get_args(self):
+        return self._args
+    kernel = property(get_kernel, set_kernel)
+    args = property(get_args)
+
+    def set_initrd(self, val):
+        self._initrd = get_path(val)
+    def get_initrd(self):
+        return self._initrd
+    initrd = property(get_initrd, set_initrd)
+
+    # set up command handlers
+    commands = { "title": "self.title",
+                 "root": "self.root",
+                 "rootnoverify": "self.root",
+                 "kernel": "self.kernel",
+                 "initrd": "self.initrd",
+                 "chainloader": None,
+                 "module": None}
+        
+
+class GrubConfigFile(object):
+    def __init__(self, fn = None):
+        self.filename = fn
+        self.images = []
+        self.timeout = -1
+
+        if fn is not None:
+            self.parse()
+
+    def parse(self, buf = None):
+        if buf is None:
+            if self.filename is None:
+                raise ValueError, "No config file defined to parse!"
+
+            f = open(self.filename, 'r')
+            lines = f.readlines()
+            f.close()
+        else:
+            lines = buf.split("\n")
+
+        img = []
+        for l in lines:
+            l = l.strip()
+            # skip blank lines
+            if len(l) == 0:
+                continue
+            # skip comments
+            if l.startswith('#'):
+                continue
+            # new image
+            if l.startswith("title"):
+                if len(img) > 0:
+                    self.images.append(GrubImage(img))
+                img = [l]
+                continue
+                
+            if len(img) > 0:
+                img.append(l)
+                continue
+
+            try:
+                (com, arg) = grub_split(l, 1)
+            except ValueError:
+                com = l
+                arg = ""
+
+            if self.commands.has_key(com):
+                if self.commands[com] is not None:
+                    exec("%s = r\"%s\"" %(self.commands[com], arg.strip()))
+                else:
+                    logging.info("Ignored directive %s" %(com,))
+            else:
+                logging.warning("Unknown directive %s" %(com,))
+                
+        if len(img) > 0:
+            self.images.append(GrubImage(img))
+
+    def _get_default(self):
+        return self._default
+    def _set_default(self, val):
+        if val == "saved":
+            self._default = -1
+        else:
+            self._default = int(val)
+
+        if self._default < 0:
+            raise ValueError, "default must be positive number"
+    default = property(_get_default, _set_default)
+
+    def set_splash(self, val):
+        self._splash = get_path(val)
+    def get_splash(self):
+        return self._splash
+    splash = property(get_splash, set_splash)
+
+    # set up command handlers
+    commands = { "default": "self.default",
+                 "timeout": "self.timeout",
+                 "fallback": "self.fallback",
+                 "hiddenmenu": "self.hiddenmenu",
+                 "splashimage": "self.splash",
+                 "password": "self.password" }
+    for c in ("bootp", "color", "device", "dhcp", "hide", "ifconfig",
+              "pager", "partnew", "parttype", "rarp", "serial",
+              "setkey", "terminal", "terminfo", "tftpserver", "unhide"):
+        commands[c] = None
+    del c
+
+
+if __name__ == "__main__":
+    if sys.argv < 2:
+        raise RuntimeError, "Need a grub.conf to read"
+    g = GrubConfigFile(sys.argv[1])
+    for i in g.images:
+        print i #, i.title, i.root, i.kernel, i.args, i.initrd
diff --git a/tools/pygrub/src/__init__.py b/tools/pygrub/src/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/tools/pygrub/src/fsys/__init__.py b/tools/pygrub/src/fsys/__init__.py
new file mode 100644 (file)
index 0000000..6d76301
--- /dev/null
@@ -0,0 +1,61 @@
+#
+# Copyright 2005 Red Hat, Inc.
+# Jeremy Katz <katzj@xxxxxxxxxx>
+#
+# This software may be freely redistributed under the terms of the GNU
+# general public license.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+import os
+import sys
+
+fstypes = {}
+
+def register_fstype(x):
+    if x.name in fstypes.keys():
+        return
+    fstypes[x.name] = x
+
+class FileSystemType(object):
+    """A simple representation for a file system that gives a fs name
+    and a method for sniffing a file to see if it's of the given fstype."""
+    def __init__(self):
+        self.name = ""
+
+    def sniff_magic(self, fn, offset = 0):
+        """Look at the filesystem at fn for the appropriate magic starting at
+        offset offset."""
+        raise RuntimeError, "sniff_magic not implemented"
+
+    def open_fs(self, fn, offset = 0):
+        """Open the given filesystem and return a filesystem object."""
+        raise RuntimeError, "open_fs not implemented"
+
+class FileSystem(object):
+    def open(self, name, flags = 0, block_size = 0):
+        """Open the fsys on name with given flags and block_size."""
+        raise RuntimeError, "open not implemented"
+
+    def close(self):
+        """Close the fsys."""
+        raise RuntimeError, "close not implemented"
+
+    def open_file(self, file, flags = None):
+        """Open the file 'name' with the given flags.  The returned object
+        should look similar to a native file object."""
+        raise RuntimeError, "open_file not implemented"
+    
+
+
+mydir = sys.modules['grub.fsys'].__path__[0]
+for f in os.listdir(mydir):
+    if not os.path.isdir("%s/%s" %(mydir, f)):
+        continue
+    try:
+        exec "import grub.fsys.%s" %(f,)        
+    except ImportError, e:
+        pass
diff --git a/tools/pygrub/src/fsys/ext2/__init__.py b/tools/pygrub/src/fsys/ext2/__init__.py
new file mode 100644 (file)
index 0000000..ff8f7af
--- /dev/null
@@ -0,0 +1,38 @@
+# Copyright 2005 Red Hat, Inc.
+# Jeremy Katz <katzj@redhat.com>
+#
+# This software may be freely redistributed under the terms of the GNU
+# general public license.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+from grub.fsys import register_fstype, FileSystemType
+from _pyext2 import *
+
+import os, struct
+
+class Ext2FileSystemType(FileSystemType):
+    def __init__(self):
+        FileSystemType.__init__(self)
+        self.name = "ext2"
+
+    def sniff_magic(self, fn, offset = 0):
+        fd = os.open(fn, os.O_RDONLY)
+        os.lseek(fd, offset, 0)
+        buf = os.read(fd, 2048)
+        
+        if len(buf) > 1082 and \
+               struct.unpack("<H", buf[1080:1082]) == (0xef53,):
+            return True
+        return False
+
+    def open_fs(self, fn, offset = 0):
+        if not self.sniff_magic(fn, offset):
+            raise ValueError, "Not an ext2 filesystem"
+        return Ext2Fs(fn)
+
+register_fstype(Ext2FileSystemType())
+
diff --git a/tools/pygrub/src/fsys/ext2/ext2module.c b/tools/pygrub/src/fsys/ext2/ext2module.c
new file mode 100644 (file)
index 0000000..30cfd04
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * ext2module.c - simple python binding for libext2fs
+ *
+ * Copyright 2005 Red Hat, Inc.
+ * Jeremy Katz <katzj@redhat.com>
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * general public license.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <Python.h>
+
+#include <ext2fs/ext2fs.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#if (PYTHON_API_VERSION >= 1011)
+#define PY_PAD 0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L,0L
+#else
+#define PY_PAD 0L,0L,0L,0L
+#endif
+
+
+/* global error object */
+PyObject *Ext2Error;
+
+typedef struct _Ext2Fs Ext2Fs;
+struct _Ext2Fs {
+    PyObject_HEAD;
+    ext2_filsys fs;
+};
+
+typedef struct _Ext2File Ext2File;
+struct _Ext2File {
+    PyObject_HEAD;
+    ext2_file_t file;
+};
+
+/* ext2 file object */
+
+static PyObject *
+ext2_file_close (Ext2File *file, PyObject *args)
+{
+    if (file->file != NULL)
+        ext2fs_file_close(file->file);
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyObject *
+ext2_file_read (Ext2File *file, PyObject *args)
+{
+    int err, size = 0;
+    size_t n, total = 0;
+    PyObject * buffer = NULL;
+
+    if (file->file == NULL) {
+        PyErr_SetString(PyExc_ValueError, "Cannot read from closed file");
+        return NULL;
+    }
+
+    if (!PyArg_ParseTuple(args, "|i", &size))
+        return NULL;
+
+    buffer = PyString_FromStringAndSize((char *) NULL, (size) ? size : 4096);
+    if (buffer == NULL)
+        return buffer;
+    while (1) {
+        err = ext2fs_file_read(file->file, PyString_AS_STRING(buffer) + total, 
+                               (size) ? size : 4096, &n);
+        if (err) {
+            if (buffer != NULL) { Py_DECREF(buffer); }
+            Py_DECREF(buffer);
+            PyErr_SetString(PyExc_ValueError, "read error");
+            return NULL;
+        }
+
+        total += n;
+        if (n == 0)
+            break;
+
+        if (size && size == total)
+            break;
+
+        if (!size) {
+            _PyString_Resize(&buffer, total + 4096);
+        }
+    }
+
+    _PyString_Resize(&buffer, total);
+    return buffer;
+}
+
+static void
+ext2_file_dealloc (Ext2File * file)
+{
+    if (file->file != NULL)
+        ext2fs_file_close(file->file);
+    PyMem_DEL(file);
+}
+
+static struct PyMethodDef Ext2FileMethods[] = {
+        { "close",
+          (PyCFunction) ext2_file_close,
+          METH_VARARGS, NULL },
+        { "read",
+          (PyCFunction) ext2_file_read,
+          METH_VARARGS, NULL },
+       { NULL, NULL, 0, NULL } 
+};
+
+static PyObject *
+ext2_file_getattr (Ext2File * file, char * name)
+{
+        return Py_FindMethod (Ext2FileMethods, (PyObject *) file, name);
+}
+
+static char Ext2FileType__doc__[] = "This is the ext2 filesystem object";
+PyTypeObject Ext2FileType = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       0,                              /* ob_size */
+       "Ext2File",                     /* tp_name */
+       sizeof(Ext2File),               /* tp_size */
+       0,                              /* tp_itemsize */
+       (destructor) ext2_file_dealloc,         /* tp_dealloc */
+       0,                              /* tp_print */
+       (getattrfunc) ext2_file_getattr,        /* tp_getattr */
+       0,                              /* tp_setattr */
+       0,                              /* tp_compare */
+       0,                              /* tp_repr */
+       0,                              /* tp_as_number */
+       0,                              /* tp_as_sequence */
+       0,                              /* tp_as_mapping */
+       0,                              /* tp_hash */
+       0,                              /* tp_call */
+       0,                              /* tp_str */
+       0,                              /* tp_getattro */
+       0,                              /* tp_setattro */
+       0,                              /* tp_as_buffer */
+       0L,                             /* tp_flags */
+       Ext2FileType__doc__,
+       PY_PAD
+};
+
+static PyObject *
+ext2_file_open (Ext2Fs *fs, char * name, int flags)
+{
+    int err;
+    ext2_file_t f;
+    ext2_ino_t ino;
+    Ext2File * file;
+
+    file = (Ext2File *) PyObject_NEW(Ext2File, &Ext2FileType);
+    file->file = NULL;
+
+    err = ext2fs_namei_follow(fs->fs, EXT2_ROOT_INO, EXT2_ROOT_INO, name, &ino);
+    if (err) {
+        PyErr_SetString(PyExc_ValueError, "unable to open file");
+        return NULL;
+    }
+
+    err = ext2fs_file_open(fs->fs, ino, flags, &f);
+    if (err) {
+        PyErr_SetString(PyExc_ValueError, "unable to open file");
+        return NULL;
+    }
+
+    file->file = f;
+    return (PyObject *) file;
+}
+
+/* ext2fs object */
+
+static PyObject *
+ext2_fs_close (Ext2Fs *fs, PyObject *args)
+{
+    if (fs->fs != NULL)
+        ext2fs_close(fs->fs);
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyObject *
+ext2_fs_open (Ext2Fs *fs, PyObject *args, PyObject *kwargs)
+{
+    static char *kwlist[] = { "name", "flags", "superblock", 
+                              "block_size", NULL };
+    char * name;
+    int flags = 0, superblock = 0, err;
+    unsigned int block_size = 0;
+    ext2_filsys efs;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|iii", kwlist, 
+                                     &name, &flags, &superblock, &block_size))
+                                     return NULL;
+
+    if (fs->fs != NULL) {
+        PyErr_SetString(PyExc_ValueError, "already have an fs object");
+        return NULL;
+    }
+
+    err = ext2fs_open(name, flags, superblock, block_size, 
+                      unix_io_manager, &efs);
+    if (err) {
+        PyErr_SetString(PyExc_ValueError, "unable to open file");
+        return NULL;
+    }
+
+    fs->fs = efs;
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+static PyObject *
+ext2_fs_open_file (Ext2Fs *fs, PyObject *args, PyObject *kwargs)
+{
+    static char *kwlist[] = { "name", "flags", NULL };
+    char * name;
+    int flags = 0;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|i", kwlist, 
+                                     &name, &flags))
+                                     return NULL;
+
+    return ext2_file_open(fs, name, flags);
+}
+
+static void
+ext2_fs_dealloc (Ext2Fs * fs)
+{
+    if (fs->fs != NULL)
+        ext2fs_close(fs->fs);
+    PyMem_DEL(fs);
+}
+
+static struct PyMethodDef Ext2FsMethods[] = {
+        { "close",
+          (PyCFunction) ext2_fs_close,
+          METH_VARARGS, NULL },
+        { "open",
+          (PyCFunction) ext2_fs_open,
+          METH_VARARGS|METH_KEYWORDS, NULL },
+        { "open_file",
+          (PyCFunction) ext2_fs_open_file,
+          METH_VARARGS|METH_KEYWORDS, NULL },
+       { NULL, NULL, 0, NULL } 
+};
+
+static PyObject *
+ext2_fs_getattr (Ext2Fs * fs, char * name)
+{
+        return Py_FindMethod (Ext2FsMethods, (PyObject *) fs, name);
+}
+
+static char Ext2FsType__doc__[] = "This is the ext2 filesystem object";
+PyTypeObject Ext2FsType = {
+       PyObject_HEAD_INIT(&PyType_Type)
+       0,                              /* ob_size */
+       "Ext2Fs",                       /* tp_name */
+       sizeof(Ext2Fs),         /* tp_size */
+       0,                              /* tp_itemsize */
+       (destructor) ext2_fs_dealloc,   /* tp_dealloc */
+       0,                              /* tp_print */
+       (getattrfunc) ext2_fs_getattr,  /* tp_getattr */
+       0,                              /* tp_setattr */
+       0,                              /* tp_compare */
+       0,                              /* tp_repr */
+       0,                              /* tp_as_number */
+       0,                              /* tp_as_sequence */
+       0,                              /* tp_as_mapping */
+       0,                              /* tp_hash */
+       0,                              /* tp_call */
+       0,                              /* tp_str */
+       0,                              /* tp_getattro */
+       0,                              /* tp_setattro */
+       0,                              /* tp_as_buffer */
+       0L,                             /* tp_flags */
+       Ext2FsType__doc__,
+       PY_PAD
+};
+
+static PyObject *
+ext2_fs_new(PyObject *o, PyObject *args, PyObject *kwargs) 
+{
+    static char *kwlist[] = { "name", "flags", "superblock", 
+                              "block_size", NULL };
+    char * name;
+    int flags = 0, superblock = 0;
+    unsigned int block_size = 0;
+    Ext2Fs *pfs;
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|iii", kwlist, 
+                                     &name, &flags, &superblock, &block_size))
+        return NULL;
+
+    pfs = (Ext2Fs *) PyObject_NEW(Ext2Fs, &Ext2FsType);
+    if (pfs == NULL)
+        return NULL;
+    pfs->fs = NULL;
+
+    if (!ext2_fs_open(pfs, 
+                      Py_BuildValue("siii", name, flags, superblock, block_size),
+                      NULL))
+        return NULL;
+
+    return (PyObject *)pfs;
+}
+
+
+static struct PyMethodDef Ext2ModuleMethods[] = {
+    { "Ext2Fs", (PyCFunction) ext2_fs_new, METH_VARARGS|METH_KEYWORDS, NULL },
+    { NULL, NULL, 0, NULL }
+};
+
+
+void init_pyext2(void) {
+    PyObject *m, *d;
+
+    m = Py_InitModule("_pyext2", Ext2ModuleMethods);
+    d = PyModule_GetDict(m);
+
+    /*    o = PyObject_NEW(PyObject, yExt2FsConstructorType);
+    PyDict_SetItemString(d, "PyExt2Fs", o);
+    Py_DECREF(o);*/
+                      
+}
diff --git a/tools/pygrub/src/fsys/ext2/test.py b/tools/pygrub/src/fsys/ext2/test.py
new file mode 100644 (file)
index 0000000..eeb7950
--- /dev/null
@@ -0,0 +1,15 @@
+#!/usr/bin/python
+
+
+import _pyext2
+import struct, os, sys
+
+fs = _pyext2.Ext2Fs("test.img")
+
+f = fs.open_file("/boot/vmlinuz-2.6.11-1.1177_FC4")
+buf = f.read()
+o = open("vmlinuz", "wb+")
+o.write(buf)
+o.close()
+
+f.close()
diff --git a/tools/pygrub/src/pygrub b/tools/pygrub/src/pygrub
new file mode 100644 (file)
index 0000000..4439092
--- /dev/null
@@ -0,0 +1,270 @@
+#!/usr/bin/python
+#
+# pygrub - simple python-based bootloader for Xen
+#
+# Copyright 2005 Red Hat, Inc.
+# Jeremy Katz <katzj@redhat.com>
+#
+# This software may be freely redistributed under the terms of the GNU
+# general public license.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+import os, sys, string, struct, tempfile
+import logging
+
+import curses, _curses, curses.wrapper
+import getopt
+
+import grub.GrubConf
+import grub.fsys
+
+PYGRUB_VER = 0.02
+
+
+def draw_window():
+    stdscr = curses.initscr()
+    curses.use_default_colors()
+    try:
+        curses.curs_set(0)
+    except _curses.error:
+        pass
+
+    stdscr.addstr(1, 4, "pyGRUB  version %s" %(PYGRUB_VER,))
+
+    win = curses.newwin(10, 74, 2, 1)
+    win.box()
+    win.refresh()
+
+    stdscr.addstr(12, 5, "Use the U and D keys to select which entry is highlighted.")
+    stdscr.addstr(13, 5, "Press enter to boot the selected OS. 'e' to edit the")
+    stdscr.addstr(14, 5, "commands before booting, 'a' to modify the kernel arguments ")
+    stdscr.addstr(15, 5, "before booting, or 'c' for a command line.")
+    stdscr.addch(12, 13, curses.ACS_UARROW)
+    stdscr.addch(12, 19, curses.ACS_DARROW)
+    (y, x) = stdscr.getmaxyx()
+    stdscr.move(y - 1, x - 1)
+
+    stdscr.refresh()
+    return (stdscr, win)
+
+def fill_entries(win, cfg, selected):
+    y = 0
+
+    for i in cfg.images:
+        if (0, y) > win.getmaxyx():
+            break
+        if y == selected:
+            attr = curses.A_REVERSE
+        else:
+            attr = 0
+        win.addstr(y + 1, 2, i.title.ljust(70), attr)
+        y += 1
+    win.refresh()
+
+def select(win, line):
+    win.attron(curses.A_REVERSE)
+    win.redrawln(line + 1, 1)
+    win.refresh()
+
+def is_disk_image(file):
+    fd = os.open(file, os.O_RDONLY)
+    buf = os.read(fd, 512)
+    os.close(fd)
+
+    if len(buf) >= 512 and struct.unpack("H", buf[0x1fe: 0x200]) == (0xaaff):
+        return True
+    return False
+    
+
+def get_config(fn):
+    if not os.access(fn, os.R_OK):
+        raise RuntimeError, "Unable to access %s" %(fn,)
+
+    cf = grub.GrubConf.GrubConfigFile()
+
+    if is_disk_image(fn):
+        raise RuntimeError, "appears to be a full disk image... unable to handle this yet"
+
+    # open the image and read the grub config
+    fs = None
+    for fstype in grub.fsys.fstypes.values():
+        if fstype.sniff_magic(fn):
+            fs = fstype.open_fs(fn)
+            break
+
+    if fs is not None:
+        f = fs.open_file("/boot/grub/grub.conf")
+        buf = f.read()
+        f.close()
+        fs.close()
+        # then parse the grub config
+        cf.parse(buf)
+    else:
+        # set the config file and parse it
+        cf.filename = fn
+        cf.parse()
+    
+    return cf
+
+def get_entry_idx(cf, entry):
+    # first, see if the given entry is numeric
+    try:
+        idx = string.atoi(entry)
+        return idx
+    except ValueError:
+        pass
+
+    # it's not, now check the labels for a match
+    for i in range(len(cf.images)):
+        if entry == cf.images[i].title:
+            return i
+
+    return None
+
+def main(cf = None):
+    mytime = 0
+
+    (stdscr, win) = draw_window()
+    stdscr.timeout(1000)
+    selected = cf.default
+    
+    while (mytime < int(cf.timeout)):
+        if cf.timeout != -1 and mytime != -1: 
+            stdscr.addstr(20, 5, "Will boot selected entry in %2d seconds"
+                          %(int(cf.timeout) - mytime))
+        else:
+            stdscr.addstr(20, 5, " " * 80)
+            
+        fill_entries(win, cf, selected)
+        c = stdscr.getch()
+        if mytime != -1:
+            mytime += 1
+#        if c == ord('q'):
+#            selected = -1
+#            break
+        elif c == ord('c'):
+            # FIXME: needs to go to command line mode
+            continue
+        elif c == ord('a'):
+            # FIXME: needs to go to append mode
+            continue
+        elif c == ord('e'):
+            # FIXME: needs to go to edit mode
+            continue
+        elif c in (curses.KEY_ENTER, ord('\n'), ord('\r')):
+            break
+        elif c == curses.KEY_UP:
+            mytime = -1
+            selected -= 1
+        elif c == curses.KEY_DOWN:
+            mytime = -1
+            selected += 1
+        else:
+            pass
+
+        # bound at the top and bottom
+        if selected < 0:
+            selected = 0
+        elif selected >= len(cf.images):
+            selected = len(cf.images) - 1
+
+    if selected >= 0:
+        return selected
+
+if __name__ == "__main__":
+    sel = None
+    
+    def run_main(scr, *args):
+        global sel
+        sel = main(cf)
+
+    def usage():
+        print >> sys.stderr, "Usage: %s [-q|--quiet] [--output=] [--entry=] <image>" %(sys.argv[0],)
+
+    try:
+        opts, args = getopt.gnu_getopt(sys.argv[1:], 'qh::',
+                                   ["quiet", "help", "output=", "entry="])
+    except getopt.GetoptError:
+        usage()
+        sys.exit(1)
+
+    if len(args) < 1:
+        usage()
+        sys.exit(1)
+    file = args[0]
+        
+    output = None
+    entry = None
+    interactive = True
+    for o, a in opts:
+        if o in ("-q", "--quiet"):
+            interactive = False
+        elif o in ("-h", "--help"):
+            usage()
+            sys.exit()
+        elif o in ("--output",):
+            output = a
+        elif o in ("--entry",):
+            entry = a
+            # specifying the entry to boot implies non-interactive
+            interactive = False
+
+    if output is None or output == "-":
+        fd = sys.stdout.fileno()
+    else:
+        fd = os.open(output, os.O_WRONLY)
+
+    cf = get_config(file)
+    if interactive:
+        curses.wrapper(run_main)
+    else:
+        sel = cf.default
+
+    # set the entry to boot as requested
+    if entry is not None:
+        idx = get_entry_idx(cf, entry)
+        if idx is not None and idx > 0 and idx < len(cf.images):
+            sel = idx
+
+    img = cf.images[sel]
+    print "Going to boot %s" %(img.title)
+    print "  kernel: %s" %(img.kernel[1],)
+    if img.initrd:
+        print "  initrd: %s" %(img.initrd[1],)
+
+    if is_disk_image(file):
+        raise RuntimeError, "unable to handle full disk images yet"
+
+    # read the kernel and initrd onto the hostfs
+    fs = None
+    for fstype in grub.fsys.fstypes.values():
+        if fstype.sniff_magic(file):
+            fs = fstype.open_fs(file)
+            break
+
+    if fs is None:
+        raise RuntimeError, "Unable to open filesystem"
+
+    kernel = fs.open_file(img.kernel[1],).read()
+    (tfd, fn) = tempfile.mkstemp(prefix="vmlinuz.")
+    os.write(tfd, kernel)
+    os.close(tfd)
+    sxp = "linux (kernel %s)" %(fn,)
+
+    if img.initrd:
+        initrd = fs.open_file(img.initrd[1],).read()
+        (tfd, fn) = tempfile.mkstemp(prefix="initrd.")
+        os.write(tfd, initrd)
+        os.close(tfd)
+        sxp += "(ramdisk %s)" %(fn,)
+    else:
+        initrd = None
+    sxp += "(args '%s')" %(img.args,)
+
+    sys.stdout.flush()
+    os.write(fd, sxp)
+    
diff --git a/tools/python/xen/xend/XendBootloader.py b/tools/python/xen/xend/XendBootloader.py
new file mode 100644 (file)
index 0000000..09a50f8
--- /dev/null
@@ -0,0 +1,94 @@
+#
+# XendBootloader.py - Framework to run a boot loader for picking the kernel
+#
+# Copyright 2005 Red Hat, Inc.
+# Jeremy Katz <katzj@xxxxxxxxxx>
+#
+# This software may be freely redistributed under the terms of the GNU
+# general public license.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+import os, sys, select
+import sxp
+
+from XendLogging import log
+from XendError import VmError
+
+BL_FIFO = "/var/lib/xen/xenbl"
+
+def bootloader(blexec, disk, quiet = 0, vcpus = None, entry = None):
+    """Run the boot loader executable on the given disk and return a
+    config image.
+    @param blexec  Binary to use as the boot loader
+    @param disk Disk to run the boot loader on.
+    @param quiet Run in non-interactive mode, just booting the default.
+    @param vcpus Number of vcpus for the domain.
+    @param entry Default entry to boot."""
+    
+    if not os.access(blexec, os.X_OK):
+        msg = "Bootloader isn't executable"
+        log.error(msg)
+        raise VmError(msg)
+    if not os.access(disk, os.R_OK):
+        msg = "Disk isn't accessible"
+        log.error(msg)
+        raise VmError(msg)
+
+    os.mkfifo(BL_FIFO, 0600)
+
+    child = os.fork()
+    if (not child):
+        args = [ blexec ]
+        if quiet:
+            args.append("-q")
+        args.append("--output=%s" %(BL_FIFO,))
+        if entry is not None:
+            args.append("--entry=%s" %(entry,))
+        args.append(disk)
+
+        try:
+            os.execvp(args[0], args)
+        except OSError, e:
+            print e
+            pass
+        os._exit(1)
+
+    while 1:
+        try:
+            r = os.open(BL_FIFO, os.O_RDONLY)
+        except OSError, e:
+            if e.errno == 4:
+                continue
+        break
+    ret = ""
+    while 1:
+        select.select([r], [], [])
+        s = os.read(r, 1024)
+        ret = ret + s
+        if len(s) == 0:
+            break
+        
+    (pid, status) = os.waitpid(child, 0)
+    os.close(r)
+    os.unlink(BL_FIFO)
+
+    if len(ret) == 0:
+        msg = "Boot loader didn't return any data!"
+        log.error(msg)
+        raise VmError, msg
+
+    pin = sxp.Parser()
+    pin.input(ret)
+    pin.input_eof()
+
+    config_image = pin.val
+    if vcpus and sxp.child_value(config_image, "vcpus") is None:
+        config_image.append(['vcpus', vcpus])
+
+    config = ['image', config_image]
+    return config
+
index c5f7ae3d99bcde6d771c0296af1c2af41d37263d..36d1cb887d11d30245578593444d904d0bf449e7 100644 (file)
@@ -16,11 +16,13 @@ import xen.lowlevel.xc; xc = xen.lowlevel.xc.new()
 import xen.util.ip
 from xen.util.ip import _readline, _readlines
 from xen.xend.server import channel, controller
+from xen.xend.server.blkif import blkdev_uname_to_file
 
 from server.channel import channelFactory
 import server.SrvDaemon; xend = server.SrvDaemon.instance()
 from server import messages
 
+from xen.xend.XendBootloader import bootloader
 import sxp
 from XendLogging import log
 from XendError import VmError
@@ -294,6 +296,7 @@ class XendDomainInfo:
         self.image_handler = None
         self.is_vmx = False
         self.vcpus = 1
+        self.bootloader = None
 
     def setdom(self, dom):
         """Set the domain id.
@@ -496,6 +499,7 @@ class XendDomainInfo:
             self.find_image_handler()
             self.init_domain()
             self.register_domain()
+            self.configure_bootloader()
 
             # Create domain devices.
             self.configure_backends()
@@ -674,6 +678,13 @@ class XendDomainInfo:
         memory = memory * 1024 + self.pgtable_size(memory)
         dom = xc.domain_create(dom= dom, mem_kb= memory,
                                cpu= cpu, cpu_weight= cpu_weight)
+        if self.bootloader:
+            try:
+                if kernel: os.unlink(kernel)
+                if ramdisk: os.unlink(ramdisk)
+            except OSError, e:
+                log.warning('unable to unlink kernel/ramdisk: %s' %(e,))
+
         if dom <= 0:
             raise VmError('Creating domain failed: name=%s memory=%d'
                           % (self.name, memory))
@@ -854,6 +865,13 @@ class XendDomainInfo:
             self.config.remove(['device', dev_config])
         self.deleteDevice(type, dev.getId())
 
+    def configure_bootloader(self):
+        """Configure boot loader.
+        """
+        bl = sxp.child_value(self.config, "bootloader")
+        if bl is not None:
+            self.bootloader = bl
+
     def configure_console(self):
         """Configure the vm console port.
         """
@@ -931,10 +949,30 @@ class XendDomainInfo:
             self.state = STATE_VM_OK
             self.restart_check()
             self.restart_state = STATE_RESTART_BOOTING
+            if self.bootloader:
+                self.config = self.bootloader_config()
             self.construct(self.config)
         finally:
             self.restart_state = None
 
+    def bootloader_config(self):
+        # if we're restarting with a bootloader, we need to run it
+        # FIXME: this assumes the disk is the first device and
+        # that we're booting from the first disk
+        blcfg = None
+        # FIXME: this assumes that we want to use the first disk
+        dev = sxp.child_value(self.config, "device")
+        if dev:
+            disk = sxp.child_value(dev, "uname")
+            fn = blkdev_uname_to_file(disk)
+            blcfg = bootloader(self.bootloader, fn, 1, self.vcpus)
+        if blcfg is None:
+            msg = "Had a bootloader specified, but can't find disk"
+            log.error(msg)
+            raise VmError(msg)
+        config = sxp.merge(['vm', blconfig ], self.config)
+        return config
+
     def configure_backends(self):
         """Set configuration flags if the vm is a backend for netif or blkif.
         Configure the backends to use for vbd and vif if specified.
@@ -1071,6 +1109,7 @@ def vm_image_linux(vm, image):
     if args:
         cmdline += " " + args
     ramdisk = sxp.child_value(image, "ramdisk", '')
+    log.debug("creating linux domain with cmdline: %s" %(cmdline,))
     vm.create_domain("linux", kernel, ramdisk, cmdline)
     return vm
 
@@ -1169,6 +1208,7 @@ add_config_handler('image',      vm_field_ignore)
 add_config_handler('device',     vm_field_ignore)
 add_config_handler('backend',    vm_field_ignore)
 add_config_handler('vcpus',      vm_field_ignore)
+add_config_handler('bootloader', vm_field_ignore)
 
 # Register other config handlers.
 add_config_handler('maxmem',     vm_field_maxmem)
index 10ce6c9eac156f2c434e524a947d38490c44ba00..6be499d64ef7e0a88fb8e2daac5bb5663877b648 100755 (executable)
@@ -71,6 +71,15 @@ def blkdev_segment(name):
                 'type'         : 'Disk' }
     return val
 
+def blkdev_uname_to_file(uname):
+    """Take a blkdev uname and return the corresponding filename."""
+    fn = None
+    if uname.find(":") != -1:
+        (typ, fn) = uname.split(":")
+        if typ == "phy" and not fn.startswith("/dev/"):
+            fn = "/dev/%s" %(fn,)
+    return fn
+
 def mount_mode(name):
     mode = None
     name = expand_dev_name(name)
index 82fd0b7a2212179102feb682ff66cf90d635a985..5b775d8d57ebbf70306bb32517bab5958fdda468 100644 (file)
@@ -10,6 +10,8 @@ import socket
 from xen.xend import sxp
 from xen.xend import PrettyPrint
 from xen.xend.XendClient import server, XendError
+from xen.xend.XendBootloader import bootloader
+from xen.xend.server import blkif
 
 from xen.util import console_client
 
@@ -94,6 +96,14 @@ gopts.var('name', val='NAME',
           fn=set_value, default=None,
           use="Domain name. Must be unique.")
 
+gopts.var('bootloader', val='FILE',
+          fn=set_value, default=None,
+          use="Path to bootloader.")
+
+gopts.var('bootentry', val='NAME',
+          fn=set_value, default=None,
+          use="Entry to boot via boot loader")
+
 gopts.var('kernel', val='FILE',
           fn=set_value, default=None,
           use="Path to kernel image.")
@@ -252,7 +262,7 @@ def strip(pre, s):
     else:
         return s
 
-def configure_image(config, vals):
+def configure_image(opts, config, vals):
     """Create the image config.
     """
     config_image = [ vals.builder ]
@@ -272,7 +282,7 @@ def configure_image(config, vals):
     config.append(['image', config_image ])
 
     
-def configure_disks(config_devs, vals):
+def configure_disks(opts, config_devs, vals):
     """Create the config for disks (virtual block devices).
     """
     for (uname, dev, mode, backend) in vals.disk:
@@ -284,14 +294,14 @@ def configure_disks(config_devs, vals):
             config_vbd.append(['backend', backend])
         config_devs.append(['device', config_vbd])
 
-def configure_pci(config_devs, vals):
+def configure_pci(opts, config_devs, vals):
     """Create the config for pci devices.
     """
     for (bus, dev, func) in vals.pci:
         config_pci = ['pci', ['bus', bus], ['dev', dev], ['func', func]]
         config_devs.append(['device', config_pci])
 
-def configure_usb(config_devs, vals):
+def configure_usb(opts, config_devs, vals):
     for path in vals.usb:
         config_usb = ['usb', ['path', path]]
         config_devs.append(['device', config_usb])
@@ -315,7 +325,7 @@ def randomMAC():
             random.randint(0x00, 0xff) ]
     return ':'.join(map(lambda x: "%02x" % x, mac))
 
-def configure_vifs(config_devs, vals):
+def configure_vifs(opts, config_devs, vals):
     """Create the config for virtual network interfaces.
     """
     vifs = vals.vif
@@ -357,7 +367,7 @@ def configure_vifs(config_devs, vals):
             config_vif.append(['ip', ip])
         config_devs.append(['device', config_vif])
 
-def configure_vfr(config, vals):
+def configure_vfr(opts, config, vals):
      if not vals.ipaddr: return
      config_vfr = ['vfr']
      idx = 0 # No way of saying which IP is for which vif?
@@ -365,7 +375,7 @@ def configure_vfr(config, vals):
          config_vfr.append(['vif', ['id', idx], ['ip', ip]])
      config.append(config_vfr)
 
-def configure_vmx(config_devs, vals):
+def configure_vmx(opts, config_devs, vals):
     """Create the config for VMX devices.
     """
     memmap = vals.memmap
@@ -375,7 +385,21 @@ def configure_vmx(config_devs, vals):
     config_devs.append(['device_model', device_model])
     config_devs.append(['device_config', device_config])
 
-def make_config(vals):
+def run_bootloader(opts, config, vals):
+    if not os.access(vals.bootloader, os.X_OK):
+        opts.err("Bootloader isn't executable")
+    if len(vals.disk) < 1:
+        opts.err("No disks configured and boot loader requested")
+    (uname, dev, mode, backend) = vals.disk[0]
+    file = blkif.blkdev_uname_to_file(uname)
+
+    blcfg = bootloader(vals.bootloader, file, not vals.console_autoconnect,
+                       vals.vcpus, vals.blentry)
+
+    config.append(['bootloader', vals.bootloader])
+    config.append(blcfg)
+
+def make_config(opts, vals):
     """Create the domain configuration.
     """
     
@@ -396,15 +420,19 @@ def make_config(vals):
         config.append(['restart', vals.restart])
     if vals.console:
         config.append(['console', vals.console])
-    
-    configure_image(config, vals)
+
+    if vals.bootloader:
+        run_bootloader(opts, config, vals)
+    else:
+        configure_image(opts, config, vals)
     config_devs = []
-    configure_disks(config_devs, vals)
-    configure_pci(config_devs, vals)
-    configure_vifs(config_devs, vals)
-    configure_usb(config_devs, vals)
-    configure_vmx(config_devs, vals)
+    configure_disks(opts, config_devs, vals)
+    configure_pci(opts, config_devs, vals)
+    configure_vifs(opts, config_devs, vals)
+    configure_usb(opts, config_devs, vals)
+    configure_vmx(opts, config_devs, vals)
     config += config_devs
+
     return config
 
 def preprocess_disk(opts, vals):
@@ -587,7 +615,8 @@ def main(argv):
         preprocess(opts, opts.vals)
         if not opts.getopt('name') and opts.getopt('defconfig'):
             opts.setopt('name', os.path.basename(opts.getopt('defconfig')))
-        config = make_config(opts.vals)
+        config = make_config(opts, opts.vals)
+
     if opts.vals.dryrun:
         PrettyPrint.prettyprint(config)
     else:
index be91098dbba07a10fae6490d11edd1d69f148591..89353e0e3b24971370b1bd603a2fe94f390efb4b 100644 (file)
@@ -49,7 +49,7 @@
 #include "select.h"
 
 #define MODULE_NAME "XFRD"
-
+#define DEBUG 1
 #include "debug.h"
 
 /*
@@ -1226,7 +1226,9 @@ int main(int argc, char *argv[]){
     int err = 0;
     int key = 0;
     int long_index = 0;
+#ifndef DEBUG
     static const char * LOGFILE = "/var/log/xfrd.log";
+#endif
 
 #ifndef DEBUG
     freopen(LOGFILE, "w+", stdout);